package co.edu.usbcali.banco.presentation.backEndBeans;

import co.edu.usbcali.banco.exceptions.*;
import co.edu.usbcali.banco.modelo.*;
import co.edu.usbcali.banco.modelo.dto.RetiroDTO;
import co.edu.usbcali.banco.presentation.businessDelegate.BusinessDelegatorView;
import co.edu.usbcali.banco.utilities.*;

import com.icesoft.faces.async.render.RenderManager;
import com.icesoft.faces.async.render.Renderable;
import com.icesoft.faces.component.ext.HtmlCommandButton;
import com.icesoft.faces.component.ext.HtmlInputText;
import com.icesoft.faces.component.selectinputdate.SelectInputDate;
import com.icesoft.faces.context.DisposableBean;
import com.icesoft.faces.webapp.xmlhttp.FatalRenderingException;
import com.icesoft.faces.webapp.xmlhttp.PersistentFacesState;
import com.icesoft.faces.webapp.xmlhttp.RenderingException;
import com.icesoft.faces.webapp.xmlhttp.TransientRenderingException;

import java.math.BigDecimal;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;
import java.util.Vector;

import javax.faces.event.ValueChangeEvent;
import javax.faces.model.DataModel;

/**
 * 
 * 
 * @author Zathura Code Generator http://code.google.com/p/zathura
 * 
 */
public class RetiroView extends DataSource implements Renderable,
		DisposableBean {
	private HtmlInputText txtDescripcion;
	private HtmlInputText txtMonto;
	private HtmlInputText txtNumerocuenta_Cuenta;
	private HtmlInputText txtCodigousuario_Usuario;
	private HtmlInputText txtNombreUsuario;
	private HtmlInputText txtCodigoretiro;
	private SelectInputDate txtFecha;
	private HtmlCommandButton btnSave;
	private HtmlCommandButton btnModify;
	private HtmlCommandButton btnDelete;
	private HtmlCommandButton btnClear;
	private boolean renderDataTable;
	private boolean flag = true;
	private RenderManager renderManager;
	private PersistentFacesState state = PersistentFacesState.getInstance();
	private List<Retiro> retiro;
	private List<RetiroDTO> retiroDTO;
	// creados
	private HtmlInputText txtTitularCuenta;
	private HtmlInputText txtApellidoCliente;


	public RetiroView() {
		super("");
	}

	public String action_clear() {
		txtMonto.setValue(null);
		txtMonto.setDisabled(true);
		txtTitularCuenta.setValue(null);
		txtTitularCuenta.setDisabled(true);
		txtApellidoCliente.setDisabled(true);
		txtApellidoCliente.setValue(null);
		txtCodigousuario_Usuario.setValue(null);
		txtCodigousuario_Usuario.setDisabled(true);
		txtNumerocuenta_Cuenta.setValue(null);
		txtNumerocuenta_Cuenta.setDisabled(false);
		txtNumerocuenta_Cuenta.setReadonly(false);
		btnSave.setDisabled(true);
		btnClear.setDisabled(false);

		return "";
	}

	public void listener_txtId(ValueChangeEvent event) {
		if ((event.getNewValue() != null) && !event.getNewValue().equals("")) {
			Cuenta entity = null;
			
			String cuenta = "";
			try {
				System.out.println(cuenta);
				cuenta = new String(event.getNewValue().toString());
				System.out.println(cuenta);
				entity = BusinessDelegatorView.getCuenta(new Long(cuenta));

				if (entity == null) {
					throw new Exception("El n&#250;mero de cuenta ingresado no se encuentra en el sistema, rectifique el n&#250;mero ingresado");
				} else {
					String usuario = (String)FacesUtils.getSession().getAttribute("Usuario");
					Cliente cliente = BusinessDelegatorView.getCliente(entity
							.getCliente().getCedulacliente());
					txtTitularCuenta.setValue(cliente.getNombrecliente());
					txtApellidoCliente.setValue(cliente.getApellidocliente());
					txtApellidoCliente.setReadonly(true);
					txtTitularCuenta.setReadonly(true);
					//txtTitularCuenta.setDisabled(false);
					txtCodigousuario_Usuario.setValue(usuario);
					txtCodigousuario_Usuario.setReadonly(true);
					txtMonto.setDisabled(false);
					txtNumerocuenta_Cuenta.setReadonly(true);
					btnSave.setDisabled(false);
					btnClear.setDisabled(false);

				}
			} catch (Exception e) {
				FacesUtils.addErrorMessage(e.getMessage());
			}
		}
	}

	public String action_save() {
		try {
			Date date = new Date();
			String montoStr = txtMonto.getValue().toString();
			String numeroCuenta = txtNumerocuenta_Cuenta.getValue().toString();
			String usuario = (String) FacesUtils.getSession().getAttribute(
					"Usuario");
			String descripcion = "Retiro";
			if (montoStr.trim().equals("")) {
				throw new Exception("El monto es de car&#225;cter obligatorio para realizar el retiro");
			}
			if (!Utilities.soloNumeros(montoStr)) {
				throw new Exception("El monto debe ser un valor num&#233;rico positivo");
			}
			if (new Long(montoStr) < 0) {
				throw new Exception("El monto debe ser un valor num&#233;rico positivo");
			}
			if (numeroCuenta.trim().equals("")) {
				throw new Exception("El n&#250;mero de la cuenta es de car&#225;cter obligatoria para realizar el retiro");
			}
			if (!Utilities.soloNumeros(numeroCuenta)) {
				throw new Exception("El n&#250;mero de la cuenta debe ser num&#233;rico totalmente para realizar el retiro");
			}
			Cuenta cuenta = BusinessDelegatorView.getCuenta(new Long(
					numeroCuenta));
			if (cuenta.getEstado().getCodigoestado().equals("3")) {
				throw new Exception("El retiro no es posible realizarlo debido a que la cuenta se encuentra inactiva.");
			}
			if (cuenta.getEstado().getCodigoestado().equals("2")) {

				throw new Exception("El retiro no es posible realizarlo debido a que la cuenta esta " +
						"pendiente de activacion por favor consigne la cantidad de $100.000.");
			}
			if (cuenta.getSaldo()<new Long(montoStr)){
				throw new Exception("El saldo de la cuenta no posee fondos suficientes para realizar el retiro.");
			}
			BusinessDelegatorView.saveRetiro(null, descripcion, date,
					new Long(montoStr), new Long(numeroCuenta), usuario);

			Long saldo = cuenta.getSaldo() - new Long(montoStr);

			BusinessDelegatorView.updateCuenta(cuenta.getClave(), new Long(
					numeroCuenta), saldo, cuenta.getCliente()
					.getCedulacliente(), "1");
			FacesUtils.addInfoMessage("El retiro se ha realizado con &#233;xito");
			action_clear();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		return "";
	}

	public String action_delete() {
		try {
			BusinessDelegatorView.deleteRetiro(FacesUtils
					.checkString(txtCodigoretiro));
			FacesUtils.addInfoMessage(ZMessManager.ENTITY_SUCCESFULLYDELETED);
			action_clear();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		return "";
	}

	public String action_modify() {
		try {
			BusinessDelegatorView.updateRetiro(FacesUtils
					.checkString(txtCodigoretiro), FacesUtils
					.checkString(txtDescripcion), FacesUtils
					.checkDate(txtFecha), FacesUtils.checkLong(txtMonto),
					FacesUtils.checkLong(txtNumerocuenta_Cuenta), FacesUtils
							.checkString(txtCodigousuario_Usuario));
			FacesUtils.addInfoMessage(ZMessManager.ENTITY_SUCCESFULLYMODIFIED);
			action_clear();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		return "";
	}

	public String action_modifyWitDTO(String codigoretiro, String descripcion,
			Date fecha, Long monto, Long numerocuenta_Cuenta,
			String codigousuario_Usuario) throws Exception {
		try {
			BusinessDelegatorView.updateRetiro(codigoretiro, descripcion,
					fecha, monto, numerocuenta_Cuenta, codigousuario_Usuario);
			renderManager.getOnDemandRenderer("RetiroView").requestRender();
			FacesUtils.addInfoMessage(ZMessManager.ENTITY_SUCCESFULLYMODIFIED);
		} catch (Exception e) {
			// renderManager.getOnDemandRenderer("RetiroView").requestRender();
			FacesUtils.addErrorMessage(e.getMessage());
			throw e;
		}

		return "";
	}

	public List<Retiro> getRetiro() {
		if (flag) {
			try {
				retiro = BusinessDelegatorView.getRetiro();
				flag = false;
			} catch (Exception e) {
				flag = true;
				FacesUtils.addErrorMessage(e.getMessage());
			}
		}

		return retiro;
	}

	public boolean isFlag() {
		return flag;
	}

	public void setRetiro(List<Retiro> retiro) {
		this.retiro = retiro;
	}

	public boolean isRenderDataTable() {
		try {
			if (flag) {
				if (BusinessDelegatorView.findTotalNumberRetiro() > 0) {
					renderDataTable = true;
				} else {
					renderDataTable = false;
				}
			}

			flag = false;
		} catch (Exception e) {
			renderDataTable = false;
			e.printStackTrace();
		}

		return renderDataTable;
	}

	public DataModel getData() {
		state = PersistentFacesState.getInstance();

		if (onePageDataModel == null) {
			onePageDataModel = new LocalDataModel(pageSize);
		}

		return onePageDataModel;
	}

	/**
	 * This is where the Object data is retrieved from the database and returned
	 * as a list of objects for display in the UI.
	 */
	private DataPage<Retiro> getDataPage(int startRow, int pageSize) {
		// Retrieve the total number of objects from the database. This
		// number is required by the DataPage object so the paginator will know
		// the relative location of the page data.
		int totalNumberRetiro = 0;

		try {
			totalNumberRetiro = BusinessDelegatorView.findTotalNumberRetiro()
					.intValue();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		// Calculate indices to be displayed in the ui.
		int endIndex = startRow + pageSize;

		if (endIndex > totalNumberRetiro) {
			endIndex = totalNumberRetiro;
		}

		try {
			retiro = BusinessDelegatorView.findPageRetiro(sortColumnName,
					sortAscending, startRow, endIndex - startRow);

			// Remove this Renderable from the existing render groups.
			// leaveRenderGroups();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		// Add this Renderable to the new render groups.
		// joinRenderGroups();
		// Reset the dirtyData flag.
		onePageDataModel.setDirtyData(false);
		// This is required when using Hibernate. If the SessionManager is not
		// cleared or closed objects are cached and stale objects will show up
		// in the table.
		// This way, the detached objects are reread from the database.
		// This call is not required with Hibernate, which uses a Query Hint
		// to clear the l2 cache in the DAO.
		flag = true;

		return new DataPage<Retiro>(totalNumberRetiro, startRow, retiro);
	}

	public DataModel getDataDTO() {
		state = PersistentFacesState.getInstance();

		if (onePageDataModel == null) {
			onePageDataModel = new LocalDataModelDTO(pageSize);
		}

		return onePageDataModel;
	}

	/**
	 * This is where the Object data is retrieved from the database and returned
	 * as a list of objects for display in the UI.
	 */
	private DataPage<RetiroDTO> getDataPageDTO(int startRow, int pageSize) {
		// Retrieve the total number of objects from the database. This
		// number is required by the DataPage object so the paginator will know
		// the relative location of the page data.
		int totalNumberRetiro = 0;

		try {
			totalNumberRetiro = BusinessDelegatorView.findTotalNumberRetiro()
					.intValue();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		// Calculate indices to be displayed in the ui.
		int endIndex = startRow + pageSize;

		if (endIndex > totalNumberRetiro) {
			endIndex = totalNumberRetiro;
		}

		try {
			retiro = BusinessDelegatorView.findPageRetiro(sortColumnName,
					sortAscending, startRow, endIndex - startRow);

			if (Utilities.validationsList(retiro)) {
				retiroDTO = new ArrayList<RetiroDTO>();

				for (Retiro retiroTmp : retiro) {
					RetiroDTO retiroDTO2 = new RetiroDTO();
					retiroDTO2.setCodigoretiro(retiroTmp.getCodigoretiro()
							.toString());
					retiroDTO2
							.setDescripcion((retiroTmp.getDescripcion() != null) ? retiroTmp
									.getDescripcion().toString()
									: null);
					retiroDTO2.setFecha(retiroTmp.getFecha());
					retiroDTO2
							.setMonto((retiroTmp.getMonto() != null) ? retiroTmp
									.getMonto().toString()
									: null);
					retiroDTO2.setNumerocuenta_Cuenta((retiroTmp.getCuenta()
							.getNumerocuenta() != null) ? retiroTmp.getCuenta()
							.getNumerocuenta().toString() : null);
					retiroDTO2.setCodigousuario_Usuario((retiroTmp.getUsuario()
							.getCodigousuario() != null) ? retiroTmp
							.getUsuario().getCodigousuario().toString() : null);
					retiroDTO2.setRetiro(retiroTmp);
					retiroDTO2.setRetiroView(this);
					retiroDTO.add(retiroDTO2);
				}
			}

			// Remove this Renderable from the existing render groups.
			leaveRenderGroups();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		// Add this Renderable to the new render groups.
		joinRenderGroups();
		// Reset the dirtyData flag.
		onePageDataModel.setDirtyData(false);
		// This is required when using Hibernate. If the SessionManager is not
		// cleared or closed objects are cached and stale objects will show up
		// in the table.
		// This way, the detached objects are reread from the database.
		// This call is not required with Hibernate, which uses a Query Hint
		// to clear the l2 cache in the DAO.
		flag = true;

		return new DataPage<RetiroDTO>(totalNumberRetiro, startRow, retiroDTO);
	}

	protected boolean isDefaultAscending(String sortColumn) {
		return true;
	}

	/**
	 * This method is called when a render call is made from the server. Render
	 * calls are only made to views containing an updated record. The data is
	 * marked as dirty to trigger a fetch of the updated record from the
	 * database before rendering takes place.
	 */
	public PersistentFacesState getState() {
		onePageDataModel.setDirtyData();

		return state;
	}

	/**
	 * This method is called from faces-config.xml with each new session.
	 */
	public void setRenderManager(RenderManager renderManager) {
		this.renderManager = renderManager;
	}

	public void renderingException(RenderingException arg0) {
		if (arg0 instanceof TransientRenderingException) {
		} else if (arg0 instanceof FatalRenderingException) {
			// Remove from existing Customer render groups.
			leaveRenderGroups();
		}
	}

	/**
	 * Remove this Renderable from existing uiCustomerBeans render groups.
	 * OnDemandRenderers are named/created using the underlying Customer Number.
	 */
	private void leaveRenderGroups() {
		if (Utilities.validationsList(retiroDTO)) {
			for (RetiroDTO retiroTmp : retiroDTO) {
				renderManager.getOnDemandRenderer("RetiroView").remove(this);
			}
		}
	}

	/**
	 * Add this Renderable to the new uiCustomerBeans render groups.
	 * OnDemandRenderers are named/created using the underlying Customer Number.
	 */
	private void joinRenderGroups() {
		if (Utilities.validationsList(retiroDTO)) {
			for (RetiroDTO retiroTmp : retiroDTO) {
				renderManager.getOnDemandRenderer("RetiroView").add(this);
			}
		}
	}

	public void dispose() throws Exception {
	}

	public RenderManager getRenderManager() {
		return renderManager;
	}

	public void setState(PersistentFacesState state) {
		this.state = state;
	}

	public HtmlInputText getTxtDescripcion() {
		return txtDescripcion;
	}

	public void setTxtDescripcion(HtmlInputText txtDescripcion) {
		this.txtDescripcion = txtDescripcion;
	}

	public HtmlInputText getTxtMonto() {
		return txtMonto;
	}

	public void setTxtMonto(HtmlInputText txtMonto) {
		this.txtMonto = txtMonto;
	}

	public HtmlInputText getTxtApellidoCliente() {
		return txtApellidoCliente;
	}

	public void setTxtApellidoCliente(HtmlInputText txtApellidoCliente) {
		this.txtApellidoCliente = txtApellidoCliente;
	}

	public HtmlInputText getTxtNumerocuenta_Cuenta() {
		return txtNumerocuenta_Cuenta;
	}

	public void setTxtNumerocuenta_Cuenta(HtmlInputText txtNumerocuenta_Cuenta) {
		this.txtNumerocuenta_Cuenta = txtNumerocuenta_Cuenta;
	}

	public HtmlInputText getTxtCodigousuario_Usuario() {
		return txtCodigousuario_Usuario;
	}

	public void setTxtCodigousuario_Usuario(
			HtmlInputText txtCodigousuario_Usuario) {
		this.txtCodigousuario_Usuario = txtCodigousuario_Usuario;
	}

	public HtmlInputText getTxtNombreUsuario() {
		return txtNombreUsuario;
	}

	public void setTxtNombreUsuario(HtmlInputText txtNombreUsuario) {
		this.txtNombreUsuario = txtNombreUsuario;
	}

	public SelectInputDate getTxtFecha() {
		return txtFecha;
	}

	public void setTxtFecha(SelectInputDate txtFecha) {
		this.txtFecha = txtFecha;
	}

	public HtmlInputText getTxtCodigoretiro() {
		return txtCodigoretiro;
	}

	public void setTxtCodigoretiro(HtmlInputText txtCodigoretiro) {
		this.txtCodigoretiro = txtCodigoretiro;
	}

	public HtmlCommandButton getBtnSave() {
		return btnSave;
	}

	public void setBtnSave(HtmlCommandButton btnSave) {
		this.btnSave = btnSave;
	}

	public HtmlCommandButton getBtnModify() {
		return btnModify;
	}

	public void setBtnModify(HtmlCommandButton btnModify) {
		this.btnModify = btnModify;
	}

	public HtmlCommandButton getBtnDelete() {
		return btnDelete;
	}

	public void setBtnDelete(HtmlCommandButton btnDelete) {
		this.btnDelete = btnDelete;
	}

	public HtmlCommandButton getBtnClear() {
		return btnClear;
	}

	public void setBtnClear(HtmlCommandButton btnClear) {
		this.btnClear = btnClear;
	}

	public HtmlInputText getTxtTitularCuenta() {
		return txtTitularCuenta;
	}

	public void setTxtTitularCuenta(HtmlInputText txtTitularCuenta) {
		this.txtTitularCuenta = txtTitularCuenta;
	}

	public void setRenderDataTable(boolean renderDataTable) {
		this.renderDataTable = renderDataTable;
	}

	public void setFlag(boolean flag) {
		this.flag = flag;
	}

	public List<RetiroDTO> getRetiroDTO() {
		return retiroDTO;
	}

	public void setRetiroDTO(List<RetiroDTO> retiroDTO) {
		this.retiroDTO = retiroDTO;
	}

	public TimeZone getTimeZone() {
		return java.util.TimeZone.getDefault();
	}

	/**
	 * A special type of JSF DataModel to allow a datatable and datapaginator to
	 * page through a large set of data without having to hold the entire set of
	 * data in memory at once. Any time a managed bean wants to avoid holding an
	 * entire dataset, the managed bean declares this inner class which extends
	 * PagedListDataModel and implements the fetchData method. fetchData is
	 * called as needed when the table requires data that isn't available in the
	 * current data page held by this object. This requires the managed bean
	 * (and in general the business method that the managed bean uses) to
	 * provide the data wrapped in a DataPage object that provides info on the
	 * full size of the dataset.
	 */
	private class LocalDataModel extends PagedListDataModel {
		public LocalDataModel(int pageSize) {
			super(pageSize);
		}

		public DataPage<Retiro> fetchPage(int startRow, int pageSize) {
			// call enclosing managed bean method to fetch the data
			return getDataPage(startRow, pageSize);
		}
	}

	private class LocalDataModelDTO extends PagedListDataModel {
		public LocalDataModelDTO(int pageSize) {
			super(pageSize);
		}

		public DataPage<RetiroDTO> fetchPage(int startRow, int pageSize) {
			// call enclosing managed bean method to fetch the data
			return getDataPageDTO(startRow, pageSize);
		}
	}
}
